/////////////////////////////////////////////////////////////////////////////
// Includes
#include "common.h"
#include "Renderer.h"
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
/////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
// Windows Settings
/////////////////////////////////////////////////////////////////////////////

const char* g_szWINDOW_CLASS_NAME	= "Phantasy Engine v.0.01";	//	Window Class Name
const char* g_szWINDOW_TITLE		= "Phantasy Engine v.0.01";	//	Window Title
const int	g_nWINDOW_WIDTH			= 800;				//	Window Width
const int	g_nWINDOW_HEIGHT		= 600;				//	Window Height

CRenderer cRenderer;

BOOL CheckIfAlreadyRunning(void);
BOOL RegisterWindowClass(HINSTANCE hInstance);
HWND MakeWindow(HINSTANCE hInstance);
bool GetInput(void);
/////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
//	Windowed(Debug) or Fullscreen(Release)
/////////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
const BOOL	g_bIS_WINDOWED			= TRUE;						
#else
const BOOL	g_bIS_WINDOWED			= FALSE;
#endif
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
// WinMain
/////////////////////////////////////////////////////////////////////////////
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	MSG		msg;	//	Generic message.
	HWND	hWnd;	//	Main Window Handle.

	// Check for duplicate program
	if(!hPrevInstance && CheckIfAlreadyRunning())
		return FALSE;

	// Register the window class
 	if(!RegisterWindowClass(hInstance))
 		return 0;
 
 	// Create the window
	hWnd = MakeWindow(hInstance);
 
	if(!hWnd)
		return 0;
 
 	ShowWindow(hWnd, nCmdShow);
 	UpdateWindow(hWnd);
	
	cRenderer.InitD3D(hWnd, hInstance, g_nWINDOW_WIDTH, g_nWINDOW_HEIGHT, g_bIS_WINDOWED);
	cRenderer.Initialize();

	// Main Event Loop
	while (cRenderer.Update())
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{ 
			// Test if this is a quit
			if (msg.message == WM_QUIT)
				break;

			// Translate any accelerator keys
			TranslateMessage(&msg);

			// Send the message to the window proc
			DispatchMessage(&msg);
		}

		cRenderer.Render();
	}

	PostQuitMessage(0);


	// Unregister the window class
	UnregisterClass(g_szWINDOW_CLASS_NAME, hInstance);

	// Return to Windows like this.
	return (int)(msg.wParam);
}


/////////////////////////////////////////////////////////////////////////////
// WindowProc
/////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	//	This is the main message handler of the system.
	PAINTSTRUCT	ps;			//	Used in WM_PAINT.
	HDC			hdc;		//	Handle to a device context.

	//	What is the message 
	switch(msg)
	{
		//	To skip ALT pop up menu (system menu)
	case WM_SYSKEYUP:
	case WM_SYSCHAR:
		return(0);
		break;

		//	Handle ALT+F4
	case WM_CLOSE:
		{
			// Sends us a WM_DESTROY
			DestroyWindow(hWnd);			
		}
		break;

		//	and lose/gain focus
	case WM_ACTIVATE:
		{
			//	gaining focus
			if (LOWORD(wParam) != WA_INACTIVE)
			{
				// unpause game code here
			}
			else // losing focus
			{
				// pause game code here
			}
		}
		break;

	case WM_CREATE: 
		{
			//	Do initialization here
			return(0);
		}
		break;

	case WM_PAINT:
		{
			//	Start painting
			hdc = BeginPaint(hWnd,&ps);

			//	End painting
			EndPaint(hWnd,&ps);
			return(0);
		}
		break;

	case WM_DESTROY: 
		{
			//	Kill the application			
			PostQuitMessage(0);
			return(0);
		}
		break;

	default:
		break;
	}

	//	Process any messages that we didn't take care of 
	return (DefWindowProc(hWnd, msg, wParam, lParam));
}


/////////////////////////////////////////////////////////////////////////////
//	Checks to see if the game was already running in another window.
//
//	NOTE:	Don't call this function if your game needs to have more
//			than one instance running on the same computer (i.e. client/server)
/////////////////////////////////////////////////////////////////////////////
BOOL CheckIfAlreadyRunning(void)
{
	//	Find a window of the same window class name and window title
	HWND hWnd = FindWindow(g_szWINDOW_CLASS_NAME, g_szWINDOW_TITLE);

	//	If one was found
	if (hWnd)
	{
		//	If it was minimized
		if (IsIconic(hWnd))
			//	restore it
			ShowWindow(hWnd, SW_RESTORE);

		//	Bring it to the front
		SetForegroundWindow(hWnd);

		return TRUE;
	}

	//	No other copies found running
	return FALSE;
}


/////////////////////////////////////////////////////////////////////////////
// Initializes and registers the window with the disignated attributes
/////////////////////////////////////////////////////////////////////////////
BOOL RegisterWindowClass(HINSTANCE hInstance)
{
	WNDCLASSEX	winClassEx;	//	This will describe the window class we will create.

	//	First fill in the window class structure
	winClassEx.cbSize			= sizeof(winClassEx);
	winClassEx.style			= CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
	winClassEx.lpfnWndProc		= WindowProc;
	winClassEx.cbClsExtra		= 0;
	winClassEx.cbWndExtra		= 0;
	winClassEx.hInstance		= hInstance;
	winClassEx.hIcon			= NULL;
	winClassEx.hIconSm			= NULL;
	winClassEx.hCursor			= LoadCursor(hInstance, IDC_ARROW);
	winClassEx.hbrBackground	= (HBRUSH)GetStockObject(BLACK_BRUSH);
	winClassEx.lpszMenuName		= NULL; 
	winClassEx.lpszClassName	= g_szWINDOW_CLASS_NAME;

	//	Register the window class
	return RegisterClassEx(&winClassEx);
}


/////////////////////////////////////////////////////////////////////////////
//	Creates and sizes the window appropriately depending on if 
//	the application is windowed or full screen.
/////////////////////////////////////////////////////////////////////////////
HWND MakeWindow(HINSTANCE hInstance)
{
	// Setup window style flags
	DWORD dwWindowStyleFlags = WS_VISIBLE;

	if (g_bIS_WINDOWED)
		dwWindowStyleFlags |= (DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU);
	else
		dwWindowStyleFlags |= WS_POPUP;
		
	// Setup the desired client area size
	RECT rWindow;
	rWindow.left	= 0;
	rWindow.top		= 0;
	rWindow.right	= g_nWINDOW_WIDTH;
	rWindow.bottom	= g_nWINDOW_HEIGHT;

	// Get the dimensions of a window that will have a client rect that
	// will really be the resolution we're looking for.
	AdjustWindowRectEx(&rWindow, 
		dwWindowStyleFlags,
		FALSE, 
		WS_EX_APPWINDOW);

	// Calculate the width/height of that window's dimensions
	int nWindowWidth	= rWindow.right - rWindow.left;
	int nWindowHeight	= rWindow.bottom - rWindow.top;

 	//	Create the window
	return CreateWindowEx(WS_EX_APPWINDOW,											//	Extended Style flags.
		g_szWINDOW_CLASS_NAME,									//	Window Class Name.
		g_szWINDOW_TITLE,											//	Title of the Window.
		dwWindowStyleFlags,										//	Window Style Flags.
		(GetSystemMetrics(SM_CXSCREEN)/2) - (nWindowWidth/2),		//	Window Start Point (x, y). 
		(GetSystemMetrics(SM_CYSCREEN)/2) - (nWindowHeight/2),	//		-Does the math to center the window over the desktop.
		nWindowWidth,												//	Width of Window.
		nWindowHeight,											//	Height of Window.
		NULL,														//	Handle to parent window.
		NULL,														//	Handle to menu.
		hInstance,												//	Application Instance.
		NULL);													//	Creation parameters.

}

bool GetInput( void )
{
	if(GetAsyncKeyState(VK_ESCAPE))
		return false;

	return true;
}